package com.ujoku.controller;

import com.labillusion.core.platform.web.rest.RESTController;
import com.labillusion.core.util.StringUtils;
import com.rits.cloning.Cloner;
import com.ujoku.context.ActionContext;
import com.ujoku.domain.*;
import com.ujoku.domain.admin.Parameter;
import com.ujoku.request.SearchForm;
import com.ujoku.service.*;
import com.ujoku.service.admin.ParametersService;
import com.ujoku.view.builder.SearchViewBuilder;
import com.ujoku.view.domain.Refinement;
import com.ujoku.view.domain.SearchView;
import com.ujoku.view.domain.TopWineryView;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.*;

import java.util.*;
import java.util.stream.Collectors;

/**
 * Created by greg.chen on 14-10-20.
 */
@RestController
public class SearchController extends RESTController {

    private static Logger logger = LoggerFactory.getLogger(SearchController.class);

    private static int[][] priceRange={{0,49},{50,99},{100,499},{500,999},{1000,2999},{3000,99999999}};

    @Autowired
    private GoodsService goodsService;

    @Autowired
    private GCategoryService gCategoryService;

    @Autowired
    private SearchViewBuilder searchViewBuilder;

    @Autowired
    private ActionContext actionContext;

    @Autowired
    private FavoriteService favoriteService;

    @Autowired
    private CountryService countryService;

    @Autowired
    private WineryService wineryService;

    @Autowired
    private ParametersService parametersService;

    @Autowired @Qualifier("cloner")
    private Cloner cloner;

    @RequestMapping(value="/search", method = RequestMethod.POST)
    @ResponseBody
    public SearchView search(@RequestBody SearchForm form) throws Exception {
        logger.debug(form.toString());

        List<Goods> list = goodsService.selectList();
        List<Goods> result =  cloner.deepClone(list);

        result = result.stream().filter(g-> g.getClosed() == null || !g.getClosed()).collect(Collectors.toList());

        Refinement refinement = buildRefinement();

        result = filterByPrice(form, result);

        result = filterByFreeText(form, result);

        result = filterByCategoryId(form, result);

        result = filterByCountry(form, result);

        result = filterByGrade(form, result);

        result = filterByWineryId(form,result);

        result = filterByIngredient(form,result);

        if(form.isSale()){
            result = result.stream().filter(g->g.getSales() == 1).collect(Collectors.toList());
        }

        if(form.isNew()){
            result = result.stream().filter(g-> g.getIsNew() == 1).collect(Collectors.toList());

        }

        if(form.isRecommended()){
            result=result.stream().filter(g->g.getRecommended()==1).collect(Collectors.toList());
        }

        if(form.isHot()){
            result = result.stream().filter(g->g.getHot() == 1).collect(Collectors.toList());
        }

        if(result == null || result.size() == 0){
            SearchView searchView = new SearchView();
            searchView.setRefinement(refinement);
            return searchView;
        }

        Sort(form, result);

        List<Favorite> favoriteList=getFavoriteList();

        return searchViewBuilder.builderSearchView(result,refinement,form,favoriteList);
    }

    private List<Goods> filterByIngredient(SearchForm form, List<Goods> result){
        if(StringUtils.hasText(form.getIngredient())){
            result = result.stream().filter(g-> StringUtils.hasText(g.getMgrade_ingredients()) && g.getMgrade_ingredients().contains(form.getIngredient())).collect(Collectors.toList());
        }

        return result;
    }

    private List<Goods> filterByWineryId(SearchForm form, List<Goods> result){
        if(form.getWineryId() != null && form.getWineryId()>0){
            result = result.stream().filter(g-> g.getWineryId() != null && g.getWineryId() == form.getWineryId()).collect(Collectors.toList());
        }

        return result;
    }

    private List<Goods> filterByGrade(SearchForm form, List<Goods> result){
        if(StringUtils.hasText(form.getGrade())){
            result = result.stream().filter(g-> StringUtils.hasText(g.getMgrade_grade()) && g.getMgrade_grade().contains(form.getGrade())).collect(Collectors.toList());
        }

        return result;
    }

    private List<Goods> filterByCountry(SearchForm form, List<Goods> result){
        if(StringUtils.hasText(form.getCountry())){
            result = result.stream().filter(g-> StringUtils.hasText(g.getCountry()) && g.getCountry().contains(form.getCountry())).collect(Collectors.toList());
        }
        return result;
    }

    private List<Goods> filterByCategoryId(SearchForm form, List<Goods> result) {
        if(form.getCate_id_1() > 0)
            result = result.stream().filter(
                    g -> g.getCate_id_1() != null && g.getCate_id_1() == form.getCate_id_1()
            ).collect(Collectors.toList());

        if(form.getCate_id_2()>0)
            result = result.stream().filter(
                    g ->   g.getCate_id_2() != null && g.getCate_id_2() == form.getCate_id_2()
            ).collect(Collectors.toList());

        return result;
    }

    private List<Goods> filterByFreeText(SearchForm form, List<Goods> result) {
        if(StringUtils.hasText(form.getFreeText())){
            result = result.stream().filter(g->  (g.getTags() != null && g.getTags().contains(form.getFreeText())) ||
                            g.getGoods_name().contains(form.getFreeText())
            ).collect(Collectors.toList());
        }
        return result;
    }

    private List<Goods> filterByPrice(SearchForm form, List<Goods> result) {
        if(form.getPriceRange() == null)
            return result;

        if(form.getPriceRange().length < 2)
            return result;

        if(form.getPriceRange()[0]==0 && form.getPriceRange()[1] == 0)
            return result;

        if(form.getPriceRange()[0]>0 && form.getPriceRange()[1] == 0) {
            result = result.stream().filter(g -> g.getPrice() !=null && g.getPrice() >= form.getPriceRange()[0]).collect(Collectors.toList());
            return result;
        }

        result = result.stream().filter(g -> g.getPrice() !=null && g.getPrice() >= form.getPriceRange()[0]
                && g.getPrice() <= form.getPriceRange()[1]).collect(Collectors.toList());

        return result;
    }

    private void Sort(SearchForm form, List<Goods> result) {
        if(StringUtils.hasText(form.getOrder())){
            String[] sortArr = form.getOrder().split(" ");
            String sortField = null;
            String sort = null;
            if(sortArr.length == 2){
                sortField = sortArr[0];
                sort =  form.getOrder().split(" ")[1];
            }

            final String finalSortField = sortField;
            final String finalSort = sort;
            Collections.sort(result, new Comparator<Goods>() {
                public int compare(Goods g1, Goods g2) {
                    if ("price".equals(finalSortField)) {
                        //从高到低
                        if ("desc".equals(finalSort))
                            return g2.getPrice().compareTo(g1.getPrice());
                        //从低到高
                        return g1.getPrice().compareTo(g2.getPrice());
                    } else
                        return g1.getPrice().compareTo(g2.getPrice());
                }

            });
        }
    }

    private Refinement buildRefinement() {
        Refinement refinement = new Refinement();
        refinement.setCountries(buildCountryRefinement());
        refinement.setPriceRange(buildPriceRangeRefinement());
        refinement.setWineryViewList(buildWineryRefinement());
        refinement.setGrades(buildGradeRefinement());
        refinement.setIngredient(buildIngredientRefinement());
        refinement.setCategories(buildCategoryRefinement());
        refinement.setSubCategories(buildSubCategoryRefinement());
        return refinement;
    }

    private List<String> buildPriceRangeRefinement(){
        List<String> prices=new ArrayList<>();
        for (int i=0;i<priceRange.length;i++){
            if(priceRange[i][1]>3000){
                prices.add(priceRange[i][0]+"+");
            }else {
                prices.add(priceRange[i][0]+"-"+priceRange[i][1]);
            }
        }
        return prices;
    }

    private List<String> buildCountryRefinement(){
        List<Country> countryList = countryService.selectList();
        List<String> countries=countryList.stream().map(c->c.getName()).distinct().collect(Collectors.toList());
        return countries.stream().filter(c->StringUtils.hasText(c)).collect(Collectors.toList());
    }

    private List<GCategory> buildCategoryRefinement(){
        List<GCategory> gCategories = gCategoryService.selectList();
        return gCategories.stream().filter(c->c.getParent_id() == 0).collect(Collectors.toList());
    }

    private List<GCategory> buildSubCategoryRefinement(){
        List<GCategory> gCategories = gCategoryService.selectList();
        return gCategories.stream().filter(c->c.getParent_id() > 0).collect(Collectors.toList());
    }

    private List<TopWineryView> buildWineryRefinement(){
        List<TopWineryView> wineryViewList = new ArrayList<>();
        List<Winery> wineryList = wineryService.selectList();
        wineryList.forEach(w->{
            TopWineryView wineryView = new TopWineryView();
            BeanUtils.copyProperties(w, wineryView);
            wineryViewList.add(wineryView);
        });
        return wineryViewList;
    }

    private List<String> buildGradeRefinement(){
        Parameter pGrade = parametersService.getParameterByKey("grade");
        if(pGrade==null){
            return new ArrayList<>();
        }
        return Arrays.asList(pGrade.getValue().split(","));
    }

    private List<String> buildIngredientRefinement(){
        Parameter pIngredient = parametersService.getParameterByKey("ingredient");
        if(pIngredient==null){
            return new ArrayList<>();
        }
        return Arrays.asList(pIngredient.getValue().split(","));
    }

    private List<Favorite> getFavoriteList(){
        Visitor visitor = actionContext.getCurrentVisitor();
        if(visitor==null || visitor.getUser_id() == null){
            return null;
        }

        List<Favorite> favoriteList=favoriteService.getFavoritesByUserId(visitor.getUser_id());
        return favoriteList;
    }
}
